const http = require('http');
const url = require('url');
const crypto = require('crypto');

const PORT = 8080;

function MD5(text) {
  return crypto.createHash('md5').update(text.toString()).digest('hex');
}

const typeCodeList = {
  '/404'       : (req, res) => {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.write('404 Not Found');
  },
  '/200'       : (req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.write('OK');
  },
  '/304'       : (req, res) => {
    res.writeHead(304, { 'Content-Type': 'text/plain' });
    res.write('Not Modified');
  },
  '/401/Basic' : (req, res) => {

    /**
     * authorization = Basic NDo0
     */
    const { headers: { authorization } } = req;

    if (authorization) {
      const data = new Buffer(authorization.split(' ')[1], 'base64').toString().split(':');
      const name = data[0];
      const pwd = data[1];

      if (name === '1' && pwd === '2') {
        res.writeHead(301, { 'Location': '/200' });
      } else {
        res.writeHead(401, { 'Content-Type': 'text/plain', 'WWW-Authenticate': 'Basic realm="authorization Basic"' });
      }
    } else {
      res.writeHead(401, { 'Content-Type': 'text/plain', 'WWW-Authenticate': 'Basic realm="authorization Basic"' });
    }

  },
  '/401/Digest': (req, res) => {
    /**
     * 详细算法参数产考wiki
     * link：https://zh.wikipedia.org/wiki/HTTP%E6%91%98%E8%A6%81%E8%AE%A4%E8%AF%81
     *
     * 仅实现 RFC 2069 规范的基础方式。
     * link：https://tools.ietf.org/html/rfc2069
     */

    /**
     * authorization = Digest username="2", realm="authorization Digest", nonce="0d88215d678f9950af6bcd824956bd96", uri="/401/Digest", response="64002d303707fc27eaf9fc48b22bdf1f", opaque="0d88215d678f9950af6bcd824956bd96"
     * @type {string}
     */
    const { headers: { authorization = '' } } = req;

    /**
     * authorization string to authorization Object
     *
     * @type {{
     *    "username": "2",
     *    "realm": "authorization Digest",
     *    "nonce": "9b1a22828d1e2d6f91fdf10fa0031e95",
     *    "uri": "/401/Digest",
     *    "response": "0a261bd06661b321474d3b73d6774a81",
     *    "opaque": "9b1a22828d1e2d6f91fdf10fa0031e95"
     *  }}
     */
    const data = authorization ? authorization
      .replace('Digest ', '')
      .split(', ')
      .map(v => v.split('=').reduce((f, l) => ({ [f]: l })))
      .reduce((f, l) => {
        f[Object.keys(l).shift()] = Object.values(l).shift().replace(/"/g, '');

        return f;
      }, {}) : {};

    const PWD = '2';

    const HA1 = MD5(`${data.username}:${data.realm}:${PWD}`);
    const HA2 = MD5(`${req.method}:${data.uri}`);
    const varResponse = MD5(`${HA1}:${data.nonce}:${HA2}`);
    const verType = varResponse === data.response;

    console.log(HA1, HA2, varResponse, verType);

    if (authorization) {
      if (verType) {
        res.writeHead(301, { 'Location': '/200' });
      } else {
        res.writeHead(401, {
          'Content-Type'    : 'text/plain',
          'WWW-Authenticate': `Digest realm="authorization Digest",nonce="${MD5(Date.now())}",opaque="${MD5(Date.now())}"`
        });
      }
    } else {
      res.writeHead(401, {
        'Content-Type'    : 'text/plain',
        'WWW-Authenticate': `Digest realm="authorization Digest",nonce="${MD5(Date.now())}",opaque="${MD5(Date.now())}"`
      });
    }

  },
  '/408'       : (req, res) => {
    res.writeHead(408, { 'Content-Type': 'text/plain' });
    res.write('Request Timeout');
  },
  '/500'       : (req, res) => {
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.write('Internal Server Error');
  }
};

http
  .createServer((req, res) => {
    const { pathname } = url.parse(req.url);

    const runFun = typeCodeList[pathname];

    if (runFun === undefined) {
      typeCodeList['/404'](req, res);
    } else {
      runFun(req, res);
    }

    res.end();
  })
  .listen(PORT);

console.log(`http://127.0.0.1:${PORT}`);